package it.infodea.tapestrydea.services.jcr.impl;

import it.infodea.tapestrydea.services.jcr.JcrSessionProviderService;
import it.infodea.tapestrydea.services.jcr.JcrWorkspaceService;
import it.infodea.tapestrydea.services.jcr.nodes.wrappers.JcrFileNode;
import it.infodea.tapestrydea.services.jcr.nodes.wrappers.JcrFolderNode;
import it.infodea.tapestrydea.services.jcr.nodes.wrappers.JcrRootFolderNode;
import it.infodea.tapestrydea.utils.JcrDeaConstants;

import java.io.InputStream;
import java.util.Collections;
import java.util.List;

import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.version.VersionException;

public class JcrWorkspaceServiceImpl implements JcrWorkspaceService {

	private JcrSessionProviderService providerService;

	public JcrWorkspaceServiceImpl(JcrSessionProviderService providerService) {
		super();
		this.providerService = providerService;

	}

	public JcrFileNode addFile(String parentAbsolutePath, String name, String owner, InputStream stream) throws RepositoryException {
		JcrFolderNode parent = getFolder(parentAbsolutePath);
		if (parent != null) {
			JcrFileNode newFile = parent.createFile(name, owner, stream);
			return newFile;
		} else {
			return null;
		}
	}

	public JcrFolderNode addFolder(String parentAbsolutePath, String name) throws RepositoryException {
		JcrFolderNode parent = getFolder(parentAbsolutePath);
		if (parent != null) {
			JcrFolderNode newFolder = parent.createFolder(name);
			return newFolder;
		} else {
			return null;
		}
	}

	public JcrFolderNode addRecoursiveFolders(String parentAbsolutePath, String relativePath) throws RepositoryException {

		JcrFolderNode parent = getFolder(parentAbsolutePath);
		JcrFolderNode result = null;
		if (parent != null) {
			String[] split = relativePath.split("/");
			JcrFolderNode newFolder = parent;
			for (String name : split) {
				newFolder = newFolder.createFolder(name);
				if (result == null)
					result = newFolder;
			}
		}
		return result;
	}

	public JcrFolderNode getAdminRootNode() throws RepositoryException {
		return new JcrRootFolderNode(providerService.getSession().getRootNode());
	}

	public List<JcrFolderNode> getChildFolders(String parentAbsolutePath) throws RepositoryException {
		JcrFolderNode parent = getFolder(parentAbsolutePath);
		if (parent != null) {
			return parent.getChilds();
		} else {
			return Collections.emptyList();
		}
	}

	public JcrFolderNode getUserRootNode() throws RepositoryException {
		Session session = providerService.getSession();
		String userPath = session.getUserID();
		JcrFolderNode adminRootNode = getAdminRootNode();
		JcrFolderNode userRoot = null;
		if (adminRootNode.contains(userPath)) {
			userRoot = new JcrRootFolderNode(adminRootNode.getFolder(userPath).getSurroundedNode());
		} else {
			userRoot = new JcrRootFolderNode(adminRootNode.createFolder(userPath).getSurroundedNode());
		}
		return userRoot;
	}

	public JcrFolderNode getVirtualRootNode(String virtualRootPath) throws RepositoryException {
		Session session = providerService.getSession();
		if (session == null) {
			return null;
		}
		JcrFolderNode virtualRoot = null;
		if (session.itemExists(virtualRootPath)) {
			virtualRoot = new JcrFolderNode((Node) session.getItem(virtualRootPath));
		} else {
			JcrFolderNode node = getAdminRootNode();
			if (virtualRootPath.startsWith("/"))
				virtualRootPath = virtualRootPath.substring(1);
			String[] splittedPath = virtualRootPath.split("/");
			for (String actualPath : splittedPath) {
				if (!node.contains(actualPath)) {
					node = node.createFolder(actualPath);
				} else {
					node = node.getFolder(actualPath);
				}
			}
			virtualRoot = new JcrFolderNode(node.getSurroundedNode());
		}
		return virtualRoot;
	}

	public JcrFolderNode getFolder(String absolutePath) throws PathNotFoundException, RepositoryException {
		JcrFolderNode folderNodeDTO = null;
		Node tmp = (Node) providerService.getSession().getItem(absolutePath);
		if ("/".equals(absolutePath) || checkFolder(tmp)) {
			folderNodeDTO = new JcrFolderNode(tmp);
		}

		return folderNodeDTO;
	}

	public JcrFileNode getFile(String absolutePath) throws PathNotFoundException, RepositoryException {
		JcrFileNode fileNodeDTO = null;
		Node tmp = (Node) providerService.getSession().getItem(absolutePath);
		if (checkFile(tmp)) {
			fileNodeDTO = new JcrFileNode(tmp);
		}

		return fileNodeDTO;
	}

	public JcrFolderNode getFolderByUUID(String uuid) throws ItemNotFoundException, RepositoryException {
		JcrFolderNode folderNodeDTO = null;
		Node tmp = providerService.getSession().getNodeByUUID(uuid);
		if (checkFolder(tmp)) {
			folderNodeDTO = new JcrFolderNode(tmp);
		}

		return folderNodeDTO;
	}

	public JcrFileNode getFileByUUID(String uuid) throws ItemNotFoundException, RepositoryException {
		JcrFileNode fileNodeDTO = null;
		Node tmp = (Node) providerService.getSession().getNodeByUUID(uuid);
		if (checkFile(tmp)) {
			fileNodeDTO = new JcrFileNode(tmp);
		}
		return fileNodeDTO;
	}

	public void removeNode(String absolutePath) throws AccessDeniedException, ItemExistsException, ConstraintViolationException,
			InvalidItemStateException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException {
		((Node) providerService.getSession().getItem(absolutePath)).remove();
		providerService.getSession().save();

	}

	private boolean checkFolder(Node tmp) throws ValueFormatException, PathNotFoundException, RepositoryException {
		String primaryType = tmp.getProperty(JcrDeaConstants.JCR_PRIMARY_TYPE_ATTR).getString();
		return JcrDeaConstants.FOLDER_PRIMARY_TYPE.equals(primaryType);
	}

	private boolean checkFile(Node tmp) throws ValueFormatException, PathNotFoundException, RepositoryException {
		String primaryType = tmp.getProperty(JcrDeaConstants.JCR_PRIMARY_TYPE_ATTR).getString();
		return JcrDeaConstants.FILE_PRIMARY_TYPE.equals(primaryType);
	}

}
